package controlsystem;

import java.util.Calendar;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

import tracksystem.Activity;
import tracksystem.SchoolActivity;
import managesystem.Student;
import controlsystem.Course;

/**
 * @author 
 * Berekent de statistieken 
 * De tijd is altijd in miliseconden
 */


public class StatisticsController {

	private Student currentStudent;
	private static final double convToHours = 1/(1000*60*60);
	
	/**
	 * constructor
	 * @param currentStudent
	 */
	public StatisticsController(Student currentStudent){
		this.currentStudent = currentStudent;
	}
	
	/** Genereert totale tijd per vak
	* @return Hashmap met Vakken en tijd per vak
	*/
	public HashMap<Course,Long> getTimePerCourse(){
		HashMap<Course,Long> timePerCourse = new HashMap<Course, Long>();
		ArrayList<Course> courses = currentStudent.getCourses();
		//een hashmap vullen met de vakken en tijden
		Iterator<Course> iterator = courses.iterator();
		while(iterator.hasNext() == true){
			Course course = iterator.next();
			long time = timeOfCourse(course);
			timePerCourse.put(course, time);
		}
		return timePerCourse;
	}
	
	/**
	 * berekend de tijd die besteed is aan een vak
	 * @param course het vak waarvoor de tijd berekend moet worden
	 * @return de tijd die besteed is
	 */
	private long timeOfCourse(Course course){
		ArrayList<SchoolActivity> activities = getSchoolActivities(); //de lijst van activiteiten ophalen
		//de totale tijd berekenen door alle activiteiten te controlleren of ze 
		//dezelfde course bevatten
		long time = 0;
		Iterator<SchoolActivity> iterator = activities.iterator();
		while(iterator.hasNext() == true){
			SchoolActivity activity = iterator.next();
			if(activity.getCourse() == course){
				time = time + activity.getDuration();
			}
		}
		return time;
	}
	
	/**
	 * selecteerd enkel de schoolactiviteiten
	 * @return
	 */
	private ArrayList<SchoolActivity> getSchoolActivities(){
		Collection<Activity> activities = currentStudent.getActivities();
		ArrayList<SchoolActivity> schoolActivities = new ArrayList<SchoolActivity>();
		//selecteren van de schoolactiviteiten
		Iterator<Activity> iterator = activities.iterator();
		while(iterator.hasNext() == true){
			if(iterator.next() instanceof SchoolActivity) {
				schoolActivities.add((SchoolActivity) iterator.next());
			}
		}
		return schoolActivities;
	}
	
	/** Genereert totale gestudeerde tijd ten opzichte van ideale tijd per vak
	* @return Hashmap gestudeerde tijd, ideale tijd
	*/
	public HashMap<Long,Long> getTimeVsIdeal(Course course){
		long ideal = course.getStudyPoints()*(27500*60*60);
		long time = timeOfCourse(course);
		HashMap<Long,Long> timeVsIdeal = new HashMap<Long,Long>();
		timeVsIdeal.put(time, ideal);
		return timeVsIdeal;
	}
	
	/** Genereert de top buddies
	* @return Hashmap met buddies en bijhorend aantal uren met op eerste plaats de buddy met minst
	* aantal afleidingen
	*/
	public HashMap<Student,Integer> getTopBuddies(){
		HashMap<Student, Integer> topBuddies = new HashMap<Student, Integer>();
		ArrayList<Student> buddiesStudent = getBuddies();
		int size = buddiesStudent.size();
		//de studenten ranken in een hashmap
		for(int j = 0; j<size; j++){
			Student buddy = buddiesStudent.get(0);
			Student topBuddy = buddiesStudent.get(0);
			int topBuddyPlace = 0;
			int distractions = distractionsWithBuddy(buddy);
			//selecteren van beste student in de (gereduceerde) lijst
			for(int i = 1; i<buddiesStudent.size(); i++){
				buddy = buddiesStudent.get(i);
				if(distractions >= distractionsWithBuddy(buddy)){
					distractions = distractionsWithBuddy(buddy);
					topBuddy = buddiesStudent.get(i);
					topBuddyPlace = i;
				}
			}
			buddiesStudent.remove(topBuddyPlace);
			topBuddies.put(topBuddy, distractions);
		}
		return topBuddies;
	}
	
	/**
	 * 
	 */
	private ArrayList<Student> getBuddies(){
		ArrayList<Student> buddiesStudent = new ArrayList<Student>();
		ArrayList<Activity> activities = currentStudent.getActivities();
		for(int i = 0; i<activities.size(); i++){
			Activity activity = activities.get(i);
			ArrayList<Student> buddies = activity.getBuddylist();
			for(int j = 0; j<buddies.size(); i++){
				Student buddy = buddies.get(i);
				if(buddiesStudent.contains(buddy) == false){
					buddiesStudent.add(buddy);
				}
			}
		}
		return buddiesStudent;
	}
	
	/**
	 * berekent hoeveel keer in totaal de student afgeleid is bij een buddy
	 * @param buddy
	 * @return
	 */
	private int distractionsWithBuddy(Student buddy){
		int numberOfDistractions = 0;
		ArrayList<SchoolActivity> activities = getSchoolActivities();
		for(int j = 0; j< activities.size(); j++){
			SchoolActivity activity = activities.get(j);
			ArrayList<Student> buddiesActivity = activity.getBuddylist();
			if(buddiesActivity.contains(buddy)){
				numberOfDistractions = numberOfDistractions + activity.getDistractions().size();
			}
		}
		return numberOfDistractions;
	}
	
	/** Genereert de top places
	* @return Hashmap met places en bijhorend aantal uren
	*/
	
	public HashMap<String,Integer> getTopPlaces(){
		HashMap<String, Integer> topPlaces = new HashMap<String, Integer>();
		ArrayList<String> places = getPlaces();
		int size = places.size();
		for(int j = 0; j<size; j++){
			String place = places.get(0);
			String topPlace = places.get(0);
			int topPlaceInArray = 0;
			int distractions = distractionsAtPlace(place);
			for(int i = 1; i<places.size(); i++){
				place = places.get(i);
				if(distractions >= distractionsAtPlace(place)){
					distractions = distractionsAtPlace(place);
					topPlace = places.get(i);
					topPlaceInArray = i;
				}
			}
			places.remove(topPlaceInArray);
			topPlaces.put(topPlace, distractions);
		}
		return topPlaces;
		
	}
	
	/**
	 * berekent aantal keer dat student afgeleid is geweest op een bepaalde plaats
	 * @param place
	 * @return
	 */
	private int distractionsAtPlace(String place){
		int numberOfDistractions = 0;
		ArrayList<SchoolActivity> activities = getSchoolActivities();
		for(int j = 0; j< activities.size(); j++){
			SchoolActivity activity = activities.get(j);
			ArrayList<String> placeActivity = getPlaces();
			if(placeActivity.contains(place)){
				numberOfDistractions = numberOfDistractions + activity.getDistractions().size();
			}
		}
		return numberOfDistractions;
	}
	
	/**
	 * verzamelt alle plaatsen waar dat de student gestudeerd heeft
	 * @return
	 */
	private ArrayList<String> getPlaces(){
		ArrayList<SchoolActivity> activities = getSchoolActivities();
		ArrayList<String> places = new ArrayList<String>();
		for(int i =0; i<activities.size(); i++){
			String place = activities.get(i).getPlace();
			if(places.contains(place) == false){
				places.add(place);
			}
		}
		return places;
	}
	
	
	/** Genereert de uren per week
	* @return ArrayList met als index de week van het jaar en als element bijhorend aantal uren.
	*/
	
	public ArrayList<Long> getHoursPerWeek(){
		ArrayList<SchoolActivity> activities = getSchoolActivities();
		ArrayList<Long> hoursPerWeek = new ArrayList<Long>();
		for(int i = 0; i<activities.size(); i++){
			SchoolActivity activity = activities.get(i);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(activity.getStart());
			int duration = activity.getDuration();
			long uren = duration/(1000*60*60);
			int week = calendar.get(Calendar.WEEK_OF_YEAR);
			long totalHoursPerWeek = hoursPerWeek.get(week) + uren;
			hoursPerWeek.add(week, totalHoursPerWeek);
		}
		return hoursPerWeek;
	}
	
	
	/** Genereert de uren van elk vak per oefenzitting en per hoorcollege of per studietijd
	* @return Hashmap met naam van het vak en bijhorend aantal uren
	*/
	public HashMap<String,Long> getCourseDistribution(){
		ArrayList<Course> courses = currentStudent.getCourses();
		HashMap<String, Long> courseDistribution = new HashMap<String, Long>()
		for(int i = 0; i<courses.size(); i++){
			Course course = courses.get(i);
			HashMap<String,Long> distribution = getDistribution(course);
			String name = course.getName();
			long timeH = distribution.get("hoorcolege");
			courseDistribution.put("" + name + "hoorcolege", timeH);
			long timeO = distribution.get("oefenzitting");
			courseDistribution.put("" + name + "oefenzitting", timeO);
			long timeS = distribution.get("studietijd");
			courseDistribution.put("" + name + "studietijd", timeS);
		}
		return courseDistribution;
	}
	
	/**
	 * genereert per type de tijd
	 * @param course de course waarvan per type de tijd berekend wordt
	 * @return hashmap met per type de gespendeerde tijd
	 */
	private HashMap<String,Long> getDistribution(Course course){
		HashMap<String, Long> courseDistribution = new HashMap<String, Long>();
		courseDistribution.put("hoorcolege", courseTimePerType("hoorcolege", course));
		courseDistribution.put("oefenzitting",courseTimePerType("oefenzitting", course));
		courseDistribution.put("studietijd",courseTimePerType("studietijd", course));
		return courseDistribution;
	}
	
	/**
	 * genereert de tijd gespendeerd van een type
	 * @param type "hoorcollege", "oefenzitting" of "studietijd"
	 * @param course de les waarvan de tijd berekent wordt
	 * @return
	 */
	private long courseTimePerType(String type, Course course){
		long time = 0;
		ArrayList<SchoolActivity> activities = getSchoolActivities();
		for(int i = 0; i<activities.size(); i++){
		SchoolActivity activity = activities.get(i);
			Course activityCourse = activity.getCourse();
			if(activityCourse == course && activity.getType().equals(type)){
				time = time + activity.getDuration();
			}
		}
		return time;
	}

	/** Genereert de gemiddelde rating (opgegeven bij invoegen, goed, slecht,...) van elk vak
	 * @return Hashmap met naam van het vak en bijhorende gemiddelde rating 
	 */
		
	public HashMap<String,Integer> getCourseAverageRating(){
			ArrayList<SchoolActivity> schoolActivities = getSchoolActivities();
			HashMap<String,Integer> courseRating = new HashMap<String,Integer>();
			ArrayList<Course> courses = currentStudent.getCourses();
			for(int i = 0; i != courses.size(); i++) {
				int rating = 0;
				int amountOfActivities = 0;
				int averageRating = 0;
				for(int j = 0; j != schoolActivities.size(); j++) {
					if(courses.get(i).getName().equals(schoolActivities.get(j).getCourse().getName())) {
						rating += schoolActivities.get(j).getRating();
						amountOfActivities++;
					}
				}
				if(amountOfActivities != 0) {
					averageRating = rating/amountOfActivities;
				}
				courseRating.put(courses.get(i).getName(), averageRating);
			}
			return courseRating;
		}
		
	/** Genereert de gemiddelde paginaSnelheid van elk vak
	 * @return Hashmap met naam van het vak en bijhorende pagina's per uur 
	 */
		
	public HashMap<String,Double> getAveragePageSpeed(){
			ArrayList<SchoolActivity> schoolActivities = getSchoolActivities();
			HashMap<String, Double> courseSpeed = new HashMap<String, Double>();
			ArrayList<Course> courses = currentStudent.getCourses();
			for(int i = 0; i != courses.size(); i++) {
				int pages = 0;
				long totalDuration = 0;
				double pageSpeed = 0;
				for(int j = 0; j != schoolActivities.size(); j++) {
					if(courses.get(i).getName().equals(schoolActivities.get(j).getCourse().getName())) {
						pages += schoolActivities.get(j).getPages();
						totalDuration += schoolActivities.get(j).getDuration();
					}
				}
				if(totalDuration != 0) {
					pageSpeed = pages/(totalDuration*convToHours);
				}
				courseSpeed.put(courses.get(i).getName(), pageSpeed);
			}
			return courseSpeed;
		}
		
	/** Genereert de afleidingen
	 * @return HashMap met naam van de afleiding en bijhorende aantal uur (?) 
	 */
		
	public HashMap<String,Double> getTopDistractions(){
			ArrayList<SchoolActivity> schoolActivities = getSchoolActivities();
			HashMap<String, Double> topDistractions = new HashMap<String, Double>();
			for(int i = 0; i != schoolActivities.size(); i++) {
				for(int j = 0; j != schoolActivities.get(i).getDistractions().size(); j++) {
					String distraction = schoolActivities.get(i).getDistractions().get(j);
					double hours = (schoolActivities.get(i).getDuration())*convToHours;
					addHoursToHashMap(topDistractions, distraction, hours);
				}
			}
			return topDistractions;
		}

		/** Genereert de productiefste dag van de week (maandag, dinsdag,...)
		* @return Hashmap met naam van de dag en bijhorende aantal uur 
		*/
		
		public HashMap<String,Double> getProductiveDay(){
			ArrayList<SchoolActivity> schoolActivities = getSchoolActivities();
			HashMap<String, Double> productiveDay = new HashMap<String, Double>();
			Calendar cal = Calendar.getInstance();
			for(int i = 0; i != schoolActivities.size(); i++) {
				Date date = schoolActivities.get(i).getStart();
				cal.setTime(date);
				int weekDay = cal.get(Calendar.DAY_OF_WEEK);
				double hours = (schoolActivities.get(i).getDuration())*convToHours;
				if(weekDay == 1) {
					addHoursToHashMap(productiveDay, "Maandag", hours);
				}
				if(weekDay == 2) {
					addHoursToHashMap(productiveDay, "Dinsdag", hours);
				}
				if(weekDay == 3) {
					addHoursToHashMap(productiveDay, "Woensdag", hours);
				}
				if(weekDay == 4) {
					addHoursToHashMap(productiveDay, "Donderdag", hours);
				}
				if(weekDay == 5) {
					addHoursToHashMap(productiveDay, "Vrijdag", hours);
				}
				if(weekDay == 6) {
					addHoursToHashMap(productiveDay, "Zaterdag", hours);
				}
				if(weekDay == 7) {
					addHoursToHashMap(productiveDay, "Zondag", hours);
				}
			}
			return productiveDay;
		}

/**
 * 
 * @param hashMap
 * @param key
 * @param hours
 */
		private void addHoursToHashMap(HashMap<String,Double> hashMap, String key, double hours)
		{
			if(hashMap.containsKey(key)) {
				double duration = hashMap.get(key);
				duration += hours;
				hashMap.remove(key);
				hashMap.put(key, duration);
			}
			else {
				hashMap.put(key, hours);
			}
		}
	}
